package com.lagou.edu.filter;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.RandomStringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.GatewayFilterFactory;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Component
@Slf4j
public class RequestProtectGatewayFilterFactory implements
        GatewayFilterFactory<RequestProtectGatewayFilterFactory.RequestProtectConfig> {

    private final Class<RequestProtectConfig> configClass = RequestProtectConfig.class;

    private Map<String,Cache<String, Long>> ipTimeCache = new ConcurrentHashMap<>();

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("count");
    }

    @Override
    public GatewayFilter apply(RequestProtectConfig config) {
        return ((exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();
            String address = request.getRemoteAddress().getAddress().getHostAddress();
            Cache<String, Long> timeCache = ipTimeCache.computeIfAbsent(address, h -> CacheBuilder.newBuilder()
                    .expireAfterWrite(1, TimeUnit.MINUTES)
                    .build());
            ServerHttpResponse response = exchange.getResponse();
            long timeMillis = System.currentTimeMillis();
            timeCache.put(RandomStringUtils.randomAlphanumeric(10),timeMillis);
            long beginTime = timeMillis - 60 * 1000;
            List<Long> collect = timeCache.asMap().values().stream().filter(a->a>beginTime).collect(Collectors.toList());
            int size = collect.size();
            if (size <= config.getCount()){
                return chain.filter(exchange);
            }else {
                String msg = "{\"message\":\"您频繁进行注册，请求已被拒绝\"}";
                response.setStatusCode(HttpStatus.SEE_OTHER);
                DataBuffer wrap = response.bufferFactory().wrap(msg.getBytes());
                return response.writeWith(Mono.just(wrap));
            }
        });
    }

    @Override
    public Class<RequestProtectConfig> getConfigClass() {
        return configClass;
    }

    @Override
    public RequestProtectConfig newConfig() {
        return BeanUtils.instantiateClass(this.configClass);
    }

    public static class RequestProtectConfig {
        private int count;

        public int getCount() {
            return count;
        }

        public void setCount(int count) {
            this.count = count;
        }
    }
}